// Copyright (c) XiGuan 2023
// Author： xiguan
// Email: xiguan.teng@qq.com
// Create on 2023/11/2
// TODO:
//

#include "SqlConnPool.h"

#include <Log.h>

#include <iostream>

SqlConnPool::SqlConnPool() {
  use_count_ = 0;
  free_count_ = 0;
}

SqlConnPool::~SqlConnPool() { close_pool(); }

void SqlConnPool::close_pool() {
  std::lock_guard<std::mutex> locker(mtx_);

  while (!conn_queue_.empty()) {
    auto it = conn_queue_.front();
    conn_queue_.pop();
    mysql_close(it);
  }

  mysql_library_end();
}

SqlConnPool *SqlConnPool::Instance() {
  static SqlConnPool connPool;
  return &connPool;
}

MYSQL *SqlConnPool::GetConn() {
  MYSQL *sql = nullptr;
  if (conn_queue_.empty()) {
    LOG_WARN("SqlConnPool empty buse!");
    return nullptr;
  }
  sem_wait(&sem_id_);
  {
    std::lock_guard<std::mutex> locker(mtx_);
    sql = conn_queue_.front();
    conn_queue_.pop();
  }

  return sql;
}

void SqlConnPool::init(const char *host, int port, const char *user,
                       const char *password, const char *db_name,
                       int conn_size) {
  assert(conn_size > 0);

  for (int idx = 0; idx < conn_size; ++idx) {
    MYSQL *sql = nullptr;
    sql = mysql_init(sql);
    if (!sql) {
      LOG_WARN("Mysql init error!");
      assert(sql != nullptr);
    }

    sql = mysql_real_connect(sql, host, user, password, db_name, port, nullptr,
                             0);
    if (!sql) {
      LOG_ERROR("Mysql Connect error!");
    }
    conn_queue_.push(sql);
  }
  MAX_CONN_ = conn_size;
  sem_init(&sem_id_, 0, MAX_CONN_);
}

void SqlConnPool::free_conn(MYSQL *conn) {
  assert(conn);
  std::lock_guard<std::mutex> locker(mtx_);
  conn_queue_.push(conn);
  sem_post(&sem_id_);
}

int SqlConnPool::GetFreeConnCount() {
  std::lock_guard<std::mutex> locker(mtx_);
  return conn_queue_.size();
}
